/**
 * ServiceRegistryHeartbeater.java
 */
package fss.remote.util;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.logging.Logger;

import fss.common.LookupServiceRegistry;
import fss.core.FssThrowable;
import fss.core.config.FssProperties;
import fss.remote.RemoteService;
import fss.remote.ServiceRegistry;
import fss.util.rmi.RmiId;
import fss.util.rmi.RmiUtils;

/**
 * A thread that will heartbeat a service registry.
 * 
 * @author thinh
 *
 */
public class ServiceRegistryHeartbeater extends Thread implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * The logger.
     */
    private static transient final Logger logger = Logger.getLogger(ServiceRegistryHeartbeater.class.getName());
    /**
     * A reference to the service registry.
     */
    private ServiceRegistry registry = null;
    /**
     * A reference to the remote service.
     */
    private RemoteService service = null;
    /**
     * The service registry identifier.
     */
    private RmiId registryId;
    /**
     * Heartbeat interval (seconds).
     */
    private int interval = 0;
    /**
     * Constructs a heartbeater for the specified service identifier that will 
     * heartbeat the specified service registry.
     * @param serviceId the service id.
     * @param registryId the registry id.
     */
    public ServiceRegistryHeartbeater(RmiId serviceId, RmiId registryId) {
        super(serviceId.toString());
        this.registryId = registryId;
        this.interval = FssProperties.getInstance().getServiceRegistryHeartbeatInterval();
        service = (RemoteService)RmiUtils.getRemoteObject(serviceId);
        registry = (ServiceRegistry) RmiUtils.getRemoteObject(registryId);
        
        boolean nullReg = registry == null;
        boolean nullService = service == null;
        if(registry == null || service == null) {
            throw new FssThrowable("Cannot obtain instances of RemoteService (" + serviceId + "," + nullService + ") and/or RegistryService (" + registryId + "," + nullReg + ")");
        }
    }
    @Override
    public void run() {
        logger.info("ServiceRegistryHeartbeater started: " + getName());
        while(true) {
            try {
                sleep(1000 * interval);
                try {
                    // attempt to invoke a remote method
                    registry.getId();
                } catch (RemoteException e) {
                    logger.warning("Cannot connect to Service Registry " + registryId + ": " + e.toString());
                    logger.warning("Looking up new Service Registry...");
                    
                    RmiId _registryId = LookupServiceRegistry.lookup();
                    if(_registryId == null) {
                        logger.warning("No available Service Registry is available.");
                    } else {
                        logger.info("New Service Registry found at " + _registryId);
                        registryId = _registryId;
                        registry = (ServiceRegistry) RmiUtils.getRemoteObject(_registryId);
                        registry.register(service); // re-register the service
                    }
                }
            } catch (Exception e) {
                logger.info("Thread ServiceRegistryHeartbeater interrupted.");
            }
        }
    }
}
